#include "EPollPoller.h"
#include "Logger.h"
#include <errno.h>
#include "Channel.h"
#include <string.h>
#include <unistd.h>

/**
 * @brief 
 * 表示当前channel是否在epoll上被监听，在channel中表示的是index_
 * kNew: 表示从来没有被加入到channels_（map<int, channel*>）中，也就不存在加入到epoll上监听
 * kAdded: 表示已被加入到epoll上监听
 * kDelete: 表示被删除监听， 但没有从channels_中移除
 */
// channel未添加到poller中
const int kNew = -1; // channel的成员index_ = -1
// channel已添加到poller
const int kAdded = 1;
// channel从poller中删除
const int kDeleted = 2; // 代表channel的添加与否与删除的状态

EPollPoller::EPollPoller(EventLoop* loop)
    : Poller(loop)
    , epollfd_(::epoll_create1(EPOLL_CLOEXEC))
    , events_(kInitEventListSize)
    {
        if (epollfd_ < 0) {
            LOG_FATAL("epoll_create error: %d\n", errno);
        }

    }
EPollPoller::~EPollPoller() {
    ::close(epollfd_);
}

// epoll_wait
Timestamp EPollPoller::poll(int timeoutMs, ChannelList *activeChannels) {
    // 会增加调用消耗
    LOG_INFO("func = %s => fd total count: %lu\n", __FUNCTION__, channels_.size());

    int numEvents = ::epoll_wait(epollfd_, &*events_.begin(), static_cast<int>(events_.size()), 
        timeoutMs); // 返回多少sock对象触发了事件，存储在events_中

    int saveErrno = errno; // errno是全局变量，防止其它线程的eventloop也在使用
    Timestamp now(Timestamp::now());

    if (numEvents > 0) {
        LOG_INFO("%d events happened \n", numEvents);

        fillActiveChannels(numEvents, activeChannels);//有sock对象触发事件就将其填入activeChannels

        if (numEvents == events_.size()) {
            events_.resize(events_.size() * 2);
        }
    }
    else if (numEvents == 0) {
        // nothing happened
    }
    else {
        if (saveErrno != EINTR) // 非外部中断打断
        {
            errno = saveErrno;
            LOG_ERROR("poll() err!");
        }
    }

    return now; // 具体发生事件的时间点

}

/**
 * @brief 
 *          eventloop
 *   channellist      poller
 *                channelmap -- key : fd   value : channel     
 * @param channel 
 */
// epoll_ctl
void EPollPoller::updateChannel(Channel *channel) {
    const int index = channel->index();

    LOG_INFO("func = %s  fd = %d  events = %d  index = %d\n",
    __FUNCTION__, channel->fd(), channel->events(), index);

    if (index == kNew || index == kDeleted) {
        if (index == kNew) {
            int fd = channel->fd();
            channels_[fd] = channel;
        }
        channel->set_index(kAdded);
        update(EPOLL_CTL_ADD, channel);
    }
    else { // channel 已经在poller上注册过了
        int fd = channel->fd();
        if (channel->isNonEvent()) { // 对事件不感兴趣
            update(EPOLL_CTL_DEL, channel);
            channel->set_index(kDeleted);
        } else { // 对某些事件感兴趣
            update(EPOLL_CTL_MOD, channel);
        }
    }

}


void EPollPoller::removeChannel(Channel *channel) {
    int fd = channel->fd();

    LOG_INFO("func = %s  fd = %d\n", __FUNCTION__, fd);

    channels_.erase(fd);

    int index = channel->index();
    if (index == kAdded) {
        update(EPOLL_CTL_DEL, channel);
    }

    channel->set_index(kNew);
}


// 填写活跃的连接
// activeChannels最终交给EventLoop
void EPollPoller::fillActiveChannels(int numEvents, ChannelList *activeChannels) const {
    for (int i = 0; i < numEvents; ++i) {
        Channel *channel = static_cast<Channel*>(events_[i].data.ptr);
        channel->set_revents(events_[i].events); // 给channel返回发生什么事件了，然后让channel去处理
        activeChannels->push_back(channel);
    }
}

// 更新channel通道 epoll_ctl
void EPollPoller::update(int operation, Channel *channel) {
    epoll_event event;
    memset(&event, 0, sizeof event);
    event.events = channel->events();// channel感兴趣的事件
    event.data.ptr = channel;
    int fd = channel->fd();
    event.data.fd = fd;

    if (::epoll_ctl(epollfd_, operation, fd, &event) < 0) {
        if (operation == EPOLL_CTL_DEL) {
            LOG_ERROR("epoll_ctl del error:%d\n", errno);
        } else {
            LOG_FATAL("epoll_ctl error:%d\n", errno);
        }
    }

}